﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Nomad.WebSync.Extensions;
using System.Reflection;

namespace Nomad.WebSync.Windows.Pages {
    /// <summary>
    /// Interaction logic for Contacts.xaml
    /// </summary>
    public partial class Contacts : Page {
        private const string AllCategories = "All categories";
        private ContactDataContext contacts;

        public Contacts() {
            InitializeComponent();

            this.getContactsFromServer();
        }

        private void getContactsFromServer() {
            using (var service = Services.Desktop.Connect()) {
                this.contacts = new ContactDataContext(service.GetContacts());
                this.contactsListBox.ItemsSource = this.contacts;
            }
        }
        private void locateByLetters(Label label) {
            var index = 0;
            if (label.Tag != null) {
                index = Convert.ToInt32(label.Tag);
                if (index == 3) index = 0;
            }

            var startChar = label.Content.ToString().ToCharArray()[index];
            index++; label.Tag = index;

            this.contactsListBox.SelectedIndex = ((ContactDataContext)this.contactsListBox.ItemsSource).IndexOf(startChar);
            this.contactsListBox.ScrollIntoView(this.contactsListBox.SelectedValue);
        }
        private void locateByString(string value) {
            var index = ((ContactDataContext)this.contactsListBox.ItemsSource).StartsWith(value);
            if (index == -1 && value.Length == 1)
                this.contactsListBox.SelectedIndex = -1;
            else if (index != -1)
                this.contactsListBox.SelectedIndex = index;
            this.contactsListBox.ScrollIntoView(this.contactsListBox.SelectedValue);
        }
        private void showContactDetails() {
            var contact = (ContactDataContextItem)this.contactsListBox.SelectedItem;
            NavigationService.Navigate(new ContactDetail(contact.Contact));
        }
        private void getCategories() {
            this.categoriesComboBox.Items.Clear();

            var comboBox = new ComboBoxItem() { Content = AllCategories, IsSelected = true };
            comboBox.Selected += new RoutedEventHandler(ComboBoxItem_Selected);
            this.categoriesComboBox.Items.Add(comboBox);

            var categories = this.contacts.getCategories();
            foreach (var item in categories) {
                comboBox = new ComboBoxItem() { Content = item, IsSelected = false };
                comboBox.Selected += new RoutedEventHandler(ComboBoxItem_Selected);
                this.categoriesComboBox.Items.Add(comboBox);
            }
        }
        private void filterByCategory(string category) {
            if (this.contacts == null)
                return;

            if (category == AllCategories)
                this.contactsListBox.ItemsSource = this.contacts;
            else
                this.contactsListBox.ItemsSource = this.contacts.GetByCategory(category);
        }

        private void Page_Loaded(object sender, RoutedEventArgs e) {            
            this.Cursor = Cursors.Wait;
            try {
                this.getCategories();
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void Label_MouseDown(object sender, MouseButtonEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                (sender as Label).Background = Brushes.Navy;
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void Label_MouseUp(object sender, MouseButtonEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                (sender as Label).Background = Brushes.White;
                this.locateByLetters((sender as Label));
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void searchTextBox_GotFocus(object sender, RoutedEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                if (searchTextBox.Text == "Find a name") searchTextBox.Text = "";
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void searchTextBox_LostFocus(object sender, RoutedEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                if (searchTextBox.Text == "") searchTextBox.Text = "Find a name";
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void searchTextBox_KeyUp(object sender, KeyEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                this.locateByString(searchTextBox.Text);
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void contactsListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                this.showContactDetails();
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
        private void categoriesComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {

        }

        private void ComboBoxItem_Selected(object sender, RoutedEventArgs e) {
            this.Cursor = Cursors.Wait;
            try {
                this.filterByCategory(((ComboBoxItem)sender).Content.ToString());
            } catch (Exception ex) {
                MessageBox.Show(ex.SoapMessage(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            } finally {
                this.Cursor = Cursors.Arrow;
            }
        }
    }

    class ContactDataContextItem {
        private string contactInfo;

        public WebSyncService.Contact Contact { get; set; }
        public string InfoType { get; private set; }
        public string Info {
            get {
                return this.contactInfo;
            }
            private set {
                this.contactInfo = value;
            }
        }
        public string FullName {
            get {
                return this.Contact.FileAs;
            }
        }

        public ContactDataContextItem(WebSyncService.Contact contact) {
            this.Info = String.Empty;
            this.InfoType = String.Empty;
            this.Contact = contact;

            var propertySource = new Dictionary<string, object>();
            PropertyInfo[] contactProperties = contact.GetType().GetProperties();
            foreach (var property in contactProperties) {
                if (property.CanRead) {
                    var propertyValue = property.GetValue(contact, null);
                    if (String.IsNullOrEmpty(propertyValue.ToString())) continue;

                    if (property.Name.EndsWith("TelephoneNumber")) {
                        this.Info = propertyValue.ToString();
                        this.InfoType = Convert.ToString(property.Name[0]).ToLower();
                        return;
                    }
                }
            }

            foreach (var property in contactProperties) {
                if (property.CanRead) {
                    var propertyValue = property.GetValue(contact, null);
                    if (String.IsNullOrEmpty(propertyValue.ToString())) continue;

                    if (property.Name.StartsWith("Email")) {
                        this.Info = propertyValue.ToString();
                        this.InfoType = Convert.ToString(property.Name[0]).ToLower();
                        return;
                    }
                }
            }            
        }
    }

    class ContactDataContext : List<ContactDataContextItem> {
        public ContactDataContext(WebSyncService.Contact[] contacts) {
            this.Clear();
            foreach (var item in contacts) {
                this.Add(new ContactDataContextItem(item));
            }
        }

        public int IndexOf(char startsWith) {
            if (startsWith == '#')
                return 0;

            startsWith = Char.ToUpper(startsWith);
            var item = this.FirstOrDefault(i => i.FullName.StartsWith(startsWith.ToString()));
            while ((item == null) || startsWith == 'Z') {
                startsWith++;
                item = this.FirstOrDefault(i => i.FullName.StartsWith(startsWith.ToString()));
            }
            return this.IndexOf(item);
        }
        public int StartsWith(string startsWith) {
            if (startsWith == "")
                return 0;

            var item = this.FirstOrDefault(i => i.FullName.StartsWith(startsWith, StringComparison.InvariantCultureIgnoreCase));
            return this.IndexOf(item);
        }
        public string[] getCategories() {
            var query = from item in this
                        where !String.IsNullOrEmpty(item.Contact.Categories)
                        orderby item.Contact.Categories
                        select item.Contact.Categories;

            List<string> categories = new List<string>();
            foreach (string item in query.Distinct()) {
                var itens = item.Split(',');
                foreach (var add in itens) {
                    categories.Add(add.Trim());
                }                
            }

            var result = from category in categories
                         orderby category
                         select category;

            return result.Distinct().ToArray();
        }

        public ContactDataContext GetByCategory(string category) {
            var query = from item in this
                        where item.Contact.Categories.Contains(category)
                        orderby item.FullName
                        select item.Contact;

            return new ContactDataContext(query.ToArray());
        }
    }
}
